package com.smedi.ismedi.inmail.core.port.adapter.persistence.repository.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.smedi.ismedi.constructionproject.api.dto.request.ProjectAssignmentListQueryRequest;
import com.smedi.ismedi.constructionproject.api.dto.request.ProjectListQueryRequest;
import com.smedi.ismedi.constructionproject.api.dto.response.resp.ProjectAssignmentResp;
import com.smedi.ismedi.constructionproject.api.dto.response.resp.ProjectResp;
import com.smedi.ismedi.constructionproject.api.feign.RemoteConstructionProjectFeignApi;
import com.smedi.ismedi.constructionproject.api.feign.RemoteProjectAssignmentFeignApi;
import com.smedi.ismedi.inmail.core.domain.aggregatemodel.Organization;
import com.smedi.ismedi.inmail.core.domain.aggregatemodel.Person;
import com.smedi.ismedi.inmail.core.domain.aggregatemodel.Project;
import com.smedi.ismedi.inmail.core.domain.dto.OrganizationAssignmentQuery;
import com.smedi.ismedi.inmail.core.domain.dto.OrganizationQuery;
import com.smedi.ismedi.inmail.core.domain.dto.PersonQuery;
import com.smedi.ismedi.inmail.core.domain.repository.PersonRepository;
import com.smedi.ismedi.inmail.core.port.adapter.convert.AdapterConverter;
import com.smedi.ismedi.inmail.core.port.adapter.service.OrganizationRemoteApiService;
import com.smedi.ismedi.inmail.core.port.adapter.service.impl.PersonRemoteApiImpl;
import com.smedi.ismedi.organization.api.dto.response.resp.OrganizationResp;
import com.smedi.ismedi.organization.api.feign.RemoteHrOrganizationFeignApi;
import com.smedi.ismedi.personnel.api.dto.request.OrganizationAssignmentListQueryRequest;
import com.smedi.ismedi.personnel.api.dto.response.resp.OrganizationAssignmentResp;
import com.smedi.ismedi.personnel.api.dto.response.resp.PersonResp;
import com.smedi.ismedi.personnel.api.feign.RemotePersonCoreFeignApi;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 主体院关系实现类
 *
 * @author niuyanling
 * @date 2021/08/05
 */
@Repository
@AllArgsConstructor
public class PersonRepositoryImpl implements PersonRepository {
    private final AdapterConverter adapterConverter;

    private final PersonRemoteApiImpl personRemoteApi;

    private final RemotePersonCoreFeignApi remotePersonCoreFeignApi;

    private final OrganizationRemoteApiService organizationRemoteApiService;

    private final RemoteProjectAssignmentFeignApi remoteProjectAssignmentFeignApi;

    private final RemoteConstructionProjectFeignApi remoteConstructionProjectFeignApi;

    private final RemoteHrOrganizationFeignApi remoteHrOrganizationFeignApi;

    @Override
    public Person getPersonOne(PersonQuery personQuery) {
        return null;
    }

    @Override
    public List<Person> getPersonList(PersonQuery personQuery) {
        List<Person> people = new ArrayList<>();

        List<Long> personIds = personQuery.getIds();

        if (StringUtils.isNotBlank(personQuery.getOrganizationNameLike())) {
            List<OrganizationResp> organizationResps = organizationRemoteApiService.getOrganizationList(OrganizationQuery.builder().shortNameLike(personQuery.getOrganizationNameLike()).build());
            if (CollectionUtils.isEmpty(organizationResps)) {
                return new ArrayList<>();
            }
            List<Long> organizationIds = organizationResps.stream().map(OrganizationResp::getId).collect(Collectors.toList());
            List<OrganizationAssignmentResp> organizationAssignmentResps = remotePersonCoreFeignApi.getOrganizationAssignmentList(OrganizationAssignmentListQueryRequest.builder().hrOrganizationIds(organizationIds).build()).getData();
            if (CollectionUtils.isEmpty(organizationAssignmentResps)) {
                return new ArrayList<>();
            }
            if (CollectionUtils.isEmpty(personQuery.getIds()) && ObjectUtils.isNull(personQuery.getId()) && StringUtils.isBlank(personQuery.getNameLike())) {
                personIds = organizationAssignmentResps.stream().map(OrganizationAssignmentResp::getPersonId).collect(Collectors.toList());
            } else {
                personIds = new ArrayList<>(org.apache.commons.collections4.CollectionUtils.intersection(personIds, organizationAssignmentResps.stream().map(OrganizationAssignmentResp::getPersonId).collect(Collectors.toList())));
            }
        }

        personQuery.setIds(personIds);

        List<PersonResp> personResps = personRemoteApi.getPersonList(personQuery);
        if (personResps.isEmpty()) {
            return new ArrayList<>();
        }

        personIds = personResps.stream().map(PersonResp::getId).collect(Collectors.toList());

        List<OrganizationAssignmentResp> organizationAssignmentResps = personRemoteApi.getOrganizationAssignmentList(OrganizationAssignmentQuery.builder().personIds(personIds).build());

        Set<Long> organizationIds = new HashSet<>();
        Map<Long, Long> personIdOrganizationIdMap = new HashMap<>(128);
        for (OrganizationAssignmentResp organizationAssignmentResp : organizationAssignmentResps) {
            organizationIds.add(organizationAssignmentResp.getHrOrganizationId());
            personIdOrganizationIdMap.put(organizationAssignmentResp.getPersonId(), organizationAssignmentResp.getHrOrganizationId());
        }

        List<ProjectAssignmentResp> projectAssignmentResps = remoteProjectAssignmentFeignApi.getProjectAssignmentList(ProjectAssignmentListQueryRequest.builder().personIds(new ArrayList<>(personIds)).build()).getData();
        Map<Long, List<Long>> personIdProjectIdsMap = new HashMap<>();
        Set<Long> projectIds = new HashSet<>();
        for (ProjectAssignmentResp projectAssignmentResp : projectAssignmentResps) {
            List<Long> projectIdsByPersonId = personIdProjectIdsMap.getOrDefault(projectAssignmentResp.getPersonId(), new ArrayList<>());
            projectIdsByPersonId.add(projectAssignmentResp.getProjectId());
            personIdProjectIdsMap.put(projectAssignmentResp.getPersonId(), projectIdsByPersonId);
            projectIds.add(projectAssignmentResp.getProjectId());
        }

        List<ProjectResp> projectResps = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(projectIds)) {
            projectResps = remoteConstructionProjectFeignApi.getProjectList(ProjectListQueryRequest.builder().ids(new ArrayList<>(projectIds)).build()).getData();
        }
        Map<Long, Project> idProjectMap = new HashMap<>();
        for (ProjectResp projectResp : projectResps) {
            organizationIds.add(projectResp.getHrOrganizationId());
        }

        List<OrganizationResp> organizationResps = organizationRemoteApiService.getOrganizationList(OrganizationQuery.builder().ids(new ArrayList<>(organizationIds)).build());
        Map<Long, Organization> idOrganizationMap = new HashMap<>(128);
        for (OrganizationResp organizationResp : organizationResps) {
            Organization organization = adapterConverter.organizationRespToOrganization(organizationResp);
            idOrganizationMap.put(organization.getId(), organization);
        }

        // 加载单位
        for (PersonResp personResp : personResps) {
            Person person = adapterConverter.personRespToPerson(personResp);
            person.setOrganization(idOrganizationMap.get(personIdOrganizationIdMap.get(person.getId())));
            people.add(person);
        }

        for (ProjectResp projectResp : projectResps) {
            Project project = adapterConverter.projectRespToProject(projectResp);
            project.setOrganization(idOrganizationMap.getOrDefault(projectResp.getHrOrganizationId(), new Organization(projectResp.getHrOrganizationId())));
            idProjectMap.put(projectResp.getId(), project);
        }

        for (Person person : people) {
            List<Long> projectIdsByPersonId = personIdProjectIdsMap.getOrDefault(person.getId(), new ArrayList<>());
            List<Project> projectsByPersonId = new ArrayList<>();
            for (Long projectIdByPersonId : projectIdsByPersonId) {
                projectsByPersonId.add(idProjectMap.getOrDefault(projectIdByPersonId, new Project(projectIdByPersonId)));
            }
            person.setProjects(projectsByPersonId);
        }

        return people;
    }
}
